/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package drinkcounter;

import com.google.appengine.api.datastore.KeyFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import drinkcounter.model.Drink;
import drinkcounter.model.Participant;
import drinkcounter.model.Party;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import javax.cache.Cache;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Toni
 */
public class DrinkCounterServiceImpl implements DrinkCounterService{

    private static final Logger log = LoggerFactory.getLogger(DrinkCounterServiceImpl.class);

    @Inject
    private Provider<EntityManager> emProvider;

    @Inject
    private HistoryService historyService;

    @Inject
    private Cache cache;

    @Override
    public Party startParty(String identifier) {
        EntityManager em = emProvider.get();
        try{
            Party party = new Party();
            party.setId(identifier);
            em.persist(party);
            log.info("Party {} was started!", identifier);
            return party;
        }finally{
            em.close();
        }
    }

    @Override
    public void updateParty(Party party) {
        EntityManager em = emProvider.get();
        try{
            em.merge(party);
        }finally{
            em.close();
        }
    }

    @Override
    public List<Party> listParties() {
        EntityManager em = emProvider.get();
        try{
            Query query = em.createNamedQuery("Party.list");
            return new LinkedList<Party>(query.getResultList());
        }finally{
            em.close();
        }
    }

    @Override
    public Party getParty(String identifier) {
        EntityManager em = emProvider.get();
        try{
           return getParty(em, identifier);
        }finally{
            em.close();
        }
    }

    @Override
    public List<Participant> listParticipants(String partyIdentifier) {
        EntityManager em = emProvider.get();
        try{
            return new LinkedList(getParty(em, partyIdentifier).getParticipants());
        }finally{
            em.close();
        }
    }

    private Party getParty(EntityManager em, String partyId){
        Query query = em.createNamedQuery("Party.byId");
        query.setParameter("id", partyId);
        return (Party) query.getSingleResult();
    }

    @Override
    public Participant addParticipant(Participant participant, String partyIdentifier) {
        EntityManager em = emProvider.get();
        try{
            Party party = getParty(em, partyIdentifier);
            party.addParticipant(participant);
            em.persist(participant);
            log.info("Participant with name {} was added to party {}", participant.getName(), party.getName());
            return participant;
        }finally{
            em.close();
        }
    }

    @Override
    public void addDrink(String participantIdentifier) {
        String partyId = null;
        EntityManager em = emProvider.get();
        try{
            Participant participant = getParticipant(em, participantIdentifier);
            Drink drink = new Drink();
            drink.setDrinkerKey(participant.getStoreKey());
            drink.setTimeStamp(new Date());
            em.persist(drink);
            participant.drink();
            partyId = participant.getParty().getId();
            log.info("Participant {} has drunk a drink in party {}", participant.getName(), participant.getParty().getName());
            cache.remove("display-"+partyId);
        }finally{
            em.close();
        }
        historyService.takeHistorySnapshot(partyId);
    }

    private Participant getParticipant(EntityManager em, String participantIdentifier){
        return em.find(Participant.class, KeyFactory.stringToKey(participantIdentifier));
    }

    @Override
    public List<Drink> getDrinks(String participantIdentifier) {
        EntityManager em = emProvider.get();
        try{
            Participant participant = getParticipant(em, participantIdentifier);
            Query query = em.createNamedQuery("Drink.byDrinker");
            query.setParameter("drinkerKey", participant.getStoreKey());
            return new LinkedList(query.getResultList());
        }finally{
            em.close();
        }
    }

    @Override
    public Participant getParticipant(String participantId) {
        EntityManager em = emProvider.get();
        try{
            return getParticipant(em, participantId);
        }finally{
            em.close();
        }
    }

    @Override
    public String getPartyIdForParticipant(String participantId) {
        EntityManager em = emProvider.get();
        try{
            return getParticipant(em, participantId).getParty().getId();
        }finally{
            em.close();
        }
    }

    @Override
    public void deleteParticipant(String participantId) {
        EntityManager em = emProvider.get();
        try{
            Participant participant = em.find(Participant.class, KeyFactory.stringToKey(participantId));
            List<Drink> drinks = getDrinks(participantId);
            for (Drink drink : drinks) {
                em.remove(drink);
            }
            em.remove(participant);
        }finally{
            em.close();
        }
    }

    @Override
    public void timePassed(float hours) {
        log.info("Burning alcohol of participants...");
        EntityManager em = emProvider.get();
        try{
            List<Party> parties =  em.createNamedQuery("Party.list").getResultList();
            for (Party party : parties) {
                float burnedAlcohol = 0;
                for (Participant participant : party.getParticipants()) {
                    burnedAlcohol += participant.passTime(hours);
                }
                if(burnedAlcohol > 0){
                    cache.remove("display-"+party.getId());
                    // party is still active, take a snapshot
                    historyService.takeHistorySnapshot(party.getId());
                }
            }
            
        }finally{
            em.close();
        }
    }

}
